
#include "render_common.h"

RenderCommon::RenderCommon()
{

}

RenderCommon::~RenderCommon()
{
  
}

//print a black screen
void		RenderCommon::render()
{
  int		objHit;

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  if(this->pickingMode == PICKING_MODE_ON)
    this->startPicking(this->xToPick, this->yToPick);

  glPushMatrix();
  glInitNames();
  glPushName(0);
  
  // need mode code here
  
  glPopMatrix();
  
  if(pickingMode == PICKING_MODE_ON)
    objHit = this->stopPicking(1); // name of hit object
  else
    glutSwapBuffers(); // flush drawing cmd
}

void		RenderCommon::setupRc()
{
  //glDepthFunc(GL_LESS);
  glEnable(GL_TEXTURE_2D);
  // anti aliasing
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_BLEND);
  // for points
  glEnable(GL_POINT_SMOOTH);
  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  // for lines
  glEnable(GL_LINE_SMOOTH);
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  // for polygons
  glEnable(GL_POLYGON_SMOOTH);
  glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

  // Black background
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
}

void		RenderCommon::changeSize(GLsizei w, GLsizei h)
{
  GLfloat	fAspect;

  // Prevent a divide by zero
  if(h == 0)
    h = 1;

  // Set Viewport to window dimensions
  glViewport(0, 0, w, h);

  fAspect = (GLfloat)w/(GLfloat)h;

  // Reset coordinate system
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f, fAspect, 1.0, 1000.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void		RenderCommon::printText(int x, int y, char *s, 
				float r, float g, float b)
{
  this->printText(x, y, s, r, g, b, GLUT_BITMAP_HELVETICA_10, 11);
}

void		RenderCommon::printText(int x, int y, char *s, 
					float r, float g, float b
					, void *font, int lineSpace)
{
  int lines;
  char* p;

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  glOrtho(0.0, glutGet(GLUT_WINDOW_WIDTH), 
	  0.0, glutGet(GLUT_WINDOW_HEIGHT), -1.0, 1.0);
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  glColor3f(r,g,b);
  glRasterPos2i(x, y);
  for(p = s, lines = 0; *p; p++) {
    if (*p == '\n') {
      lines++;
      glRasterPos2i(x, y - (lines*lineSpace));
    }
    else
      glutBitmapCharacter(font, *p);
  }
  glPopMatrix();
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
}

void		RenderCommon::normalKeyEvent(unsigned char key, int x, int y)
{
  switch(key)
    {
    case 32: // space
      break;
    case 27: // echap
      break;
    case 113: // q
      break;
    default:
      break;
    }
  glutPostRedisplay();
}

void		RenderCommon::specialKeyEvent(int key, int x, int y)
{
  switch(key)
    {
    case 101: // key up
      break;
    case 103: // key down
      break;
    case 100: // key left
      break;
    case 102: // key right
      break;
    case 104: // page up
      break;
    case 105: // page down
      break;
    default:
      break;
    }
   
  // Refresh the Window
  glutPostRedisplay();
}

// mouse events like click
void		RenderCommon::mouseEvent(int button, int state, int x, int y)
{
  // empty need to be implemented by daughter class
}

void		RenderCommon::mousePassiveMotion(int x, int y)
{
  this->pickingMode = PICKING_MODE_ON;
  this->xToPick = x;
  this->yToPick = y;
  
  // render select buffer
  this->render();
  // then re render the scene
  this->render();
}

void		RenderCommon::startPicking(int x, int y)
{
  GLint		viewport[4];
  float		ratio;

  glSelectBuffer(BUFSIZE, selectBuf);
  glRenderMode(GL_SELECT);

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();

  glGetIntegerv(GL_VIEWPORT,viewport);
  gluPickMatrix(x, viewport[3] - y,
		10,10,viewport);
  ratio = (viewport[2]+0.0) / viewport[3];
  gluPerspective(45,ratio,0.1,1000);
  glMatrixMode(GL_MODELVIEW);
  glInitNames();
}

int		RenderCommon::stopPicking(int level)
{
  GLint		hits;
  GLuint	names, *ptr;
  unsigned int	j;
  int		i, countMatch = 0;
    
  // restoring the original projection matrix
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glFlush();
  
  // returning to normal rendering mode
  hits = glRenderMode(GL_RENDER);
  this->pickingMode = PICKING_MODE_OFF;

  ptr = (GLuint *) selectBuf;
  for (i = 0; i < hits; i++) 
    {
      names = *ptr;
      ptr++;
      ptr++;
      if((float) *ptr/0x7fffffff > 1.0f)
	countMatch++;
      ptr++;
      for (j = 0; j < names; j++) 
	{
	  if(countMatch == level)
	    return(*ptr);
	  ptr++;
	}
    }
  return(0);
}

// draw a counter clockwise square
void		RenderCommon::drawSquareCCW(float xLco, float yLco
					    , float width, float heigh
					    , float depth
					    , float r, float g, float b
					    , float alpha ,int name)
{
  glColor4f(r, g, b, alpha);
  glLoadName(name);
  
  glBegin(GL_QUADS);
  glVertex3f(xLco, yLco - heigh, depth);
  glVertex3f(xLco + width, yLco - heigh, depth);
  glVertex3f(xLco + width, yLco, depth);
  glVertex3f(xLco, yLco, depth);
  glEnd();
}
